package handlers

import (
	"brood-agent2/conf"
	"brood-agent2/utils"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
)

func InstallNginxImpl(installer NginxInstaller) error {
	utils.Logger.Info("install nginx begin")

	err := installCheck("nginx.service")
	if err != nil {
		return err
	}

	configureArgs := []string{
		// 更多参考 docs https://nginx.org/en/docs/configure.html

		"--with-threads",                 // 启用线程池
		"--with-http_ssl_module",         // 启用https协议支持，需要openssl依赖
		"--with-http_realip_module",      // 允许将客户端地址更改为指定表头字段中发送的地址
		"--with-http_addition_module",    // 允许在响应之前和之后添加文本
		"--with-http_stub_status_module", // 提供对基本状态信息的访问
		"--with-http_gzip_static_module", // 允许发送扩展名为gz的与压缩文件
		"--with-http_sub_module",         // 允许通过将一个指定字符串替换为另一个字符串来修改响应
		"--with-http_dav_module",         // 允许通过webDav协议提供文件管理自动化
		"--with-stream",                  // 启用负载均衡
	}

	pkgName := "nginx"
	installPath := filepath.Join(installer.ApplicationDir, pkgName)
	configureArgs = append(configureArgs, fmt.Sprintf("--prefix=%s", installPath))

	// 下载Nginx
	TmpPath := conf.Conf.TmpDir + utils.GenUUID4().String()
	err = extractPkg(installer.PkgUrl.Url, TmpPath, installer.PkgUrl.ExtractType, pkgName)
	if err != nil {
		return err
	}
	nginxTmpPath := filepath.Join(TmpPath, pkgName)
	env := []string{"PATH=/usr/local/bin:/usr/bin"}

	// 下载依赖库
	for dependName, downloadInfo := range installer.DependPkg {
		// zlib 提供多种压缩及解压缩的方式，nginx可支持内容压缩
		// pcre 提供正则表达式解析，nginx可对http模块配置进行解析
		// openssl 提供密码算法、秘钥证书管理，nginx可提供https服务
		err := extractPkg(downloadInfo.Url, TmpPath, downloadInfo.ExtractType, dependName)
		if err != nil {
			return err
		}
		configureArgs = append(configureArgs, fmt.Sprintf("--with-%s=%s", dependName, filepath.Join(TmpPath, dependName)))
	}

	// 下载第三方库
	for externalName, downloadInfo := range installer.ExternalPkg {
		err := extractPkg(downloadInfo.Url, TmpPath, downloadInfo.ExtractType, externalName)
		if err != nil {
			return err
		}
		configureArgs = append(configureArgs, fmt.Sprintf("--add-module=%s", filepath.Join(TmpPath, externalName)))
	}

	// configure
	_, err = utils.ExecCmd(nginxTmpPath, env, bytes.Buffer{}, "./configure", configureArgs...)
	if err != nil {
		return err
	}

	// make
	_, err = utils.ExecCmd(nginxTmpPath, env, bytes.Buffer{}, "make")
	if err != nil {
		return err
	}

	// make install
	_, err = utils.ExecCmd(nginxTmpPath, env, bytes.Buffer{}, "make", "install")
	if err != nil {
		return err
	}

	// soft link
	err = addSoftLink(filepath.Join(installPath, "/sbin/nginx"), "/usr/bin/nginx")
	if err != nil {
		return err
	}

	// 备份原始ng配置
	err = os.Rename(filepath.Join(installPath, "/conf/nginx.conf"), filepath.Join(installPath, "/conf/nginx.conf.bak"))
	if err != nil {
		utils.Logger.Error(err)
		return err
	}

	// 下载所需配置
	for _, download := range installer.DependFiles {
		err = utils.DownloadFile(download.Url, download.SavePath, os.FileMode(0755), true)
		if err != nil {
			return err
		}
	}

	err = utils.RegisterService("nginx.service")
	if err != nil {
		return err
	}

	err = utils.RemoveAll(TmpPath)
	if err != nil {
		return err
	}

	utils.Logger.Info("install nginx done")

	return nil
}

func InstallLBNginxImpl(installer LBNginxInstaller) error {
	flag := true                   // 安装状态
	downloadPathList := []string{} // 下载的配置
	defer func() {
		// 失败回滚
		if !flag {
			for _, path := range downloadPathList {
				utils.Logger.Info(fmt.Sprintf("rollback and delete %s", path))
				_ = utils.RemoveAll(path)
			}
		}
	}()

	status, err := utils.ServiceStatus("nginx.service")
	if err != nil || status != utils.StatusRunning {
		errStr := "nginx server is not running"
		utils.Logger.Error(errStr)
		return fmt.Errorf(errStr)
	}

	for _, download := range installer.DependFiles {
		if utils.CheckDir(download.SavePath) {
			_, f := filepath.Split(download.SavePath)
			errStr := fmt.Sprintf("conf %s is already exists", f)
			utils.Logger.Error(errStr)
			flag = false
			return fmt.Errorf(errStr)
		}
		err := utils.DownloadFile(download.Url, download.SavePath, os.FileMode(0755), false)
		if err != nil {
			flag = false
			return err
		}
		downloadPathList = append(downloadPathList, download.SavePath)
	}

	_, err = utils.ExecCmd("", []string{}, bytes.Buffer{}, "nginx", "-t")
	if err != nil {
		flag = false
		return err
	}

	err = utils.RestartService("nginx.service")
	if err != nil {
		flag = false
		return err
	}

	return nil
}
